package com.enterprise.support.utility;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.dom4j.DocumentException;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import javax.xml.parsers.*;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.*;
import java.net.*;
import java.text.DecimalFormat;
import java.util.List;
import java.util.Properties;
import java.util.regex.Pattern;


/**
 * Created by IntelliJ IDEA.
 * User: Zhanggaojiang
 * Date: 11-1-19
 * Time: 上午10:36
 * Email: z82422@gmail.com
 * 文件管理 辅助对象
 */
public class FileUtility {
    private final static Logger logger = Logger.getLogger(FileUtility.class);

    public final static File TEMP_DIRECTORY = new File(Configuration.get().getString("web_fileuploader_tempdirectory"));
    public final static File DIRECTORY = new File(Configuration.get().getString("web_fileuploader_directory"));

    static {
        if (!TEMP_DIRECTORY.exists()) TEMP_DIRECTORY.mkdirs();
        if (!DIRECTORY.exists()) DIRECTORY.mkdirs();
    }

    private static DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    private static XPath xpath = XPathFactory.newInstance().newXPath();
    public static final Pattern dosSeperator = Pattern.compile("\\\\");
    public static final Pattern lastSeperator = Pattern.compile("/$");

    public static String getFileNameChop(String fullpath) {
        if (fullpath == null) return null;
        fullpath = dosSeperator.matcher(fullpath).replaceAll("/");
        int pos = fullpath.lastIndexOf("/");
        if (pos > -1) return fullpath.substring(pos + 1);
        else return fullpath;
    }

    public static String getFilePathChop(String fullpath) {
        if (fullpath == null) return null;
        fullpath = dosSeperator.matcher(fullpath).replaceAll("/");
        int pos = fullpath.lastIndexOf("/");
        if (pos > -1) return fullpath.substring(0, pos + 1);
        else return "./";
    }


    public static String getCompleteLeadingSeperator(String fullpath) {
        if (fullpath == null) return null;
        fullpath = dosSeperator.matcher(fullpath).replaceAll("/");
        if (!fullpath.endsWith(File.separator)) fullpath = fullpath + "/";
        return fullpath;
    }

    public static String getRemoveLeadingSeperator(String fileName) {
        if (fileName == null) {
            return null;
        } else {
            fileName = dosSeperator.matcher(fileName).replaceAll("/");
            fileName = lastSeperator.matcher(fileName).replaceAll("");
            return fileName;
        }
    }

    public static String getFilesizeString(long size) {
        DecimalFormat df = new DecimalFormat("#.00");
        String fileSizeString = "";
        if (size < 1024) {
            fileSizeString = df.format((double) size) + "B";
        } else if (size < 1048576) {
            fileSizeString = df.format((double) size / 1024) + "K";
        } else if (size < 1073741824) {
            fileSizeString = df.format((double) size / 1048576) + "M";
        } else {
            fileSizeString = df.format((double) size / 1073741824) + "G";
        }
        return fileSizeString;
    }

    public static String readStream(InputStream stream, String... charset) {
        StringBuffer strBuffer = new StringBuffer();
        try {
            List<String> lines = IOUtils.readLines(stream, Validation.isEmpty(charset) ? "UTF-8" : charset[0]);
            for (String line : lines) {
                strBuffer.append(line);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return strBuffer.toString();
    }

    /**
     * <b>功能:</b>彻底删除一个文件（如果是目录，则目录下的内容也将被删除）
     *
     * @param file:一个文件（或目录）
     */
    public static final void delFile(File file) {
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (int i = 0; i < files.length; i++) {
                delFile(files[i]);
            }
        }
        file.delete();
    }

    public static final void delFile(File[] files) {
        for (File file : files) {
            delFile(file);
        }
    }

    /**
     * <b>功能:</b>文件（目录）拷贝
     *
     * @param file1：源文件（或目录）
     * @param file2：目标文件（或目录）
     */
    /* 日期			版本		修订内容						修订人
    * 2006.02.19	1.0.0	加版本号						钱前
    */
    public static String copyFile(File file1, File file2) {
        String log = "";
        if (!file1.exists()) return log += "源文件不存在:" + file1.getPath();
        /*构建目标文件夹*/
        if (!file2.getParentFile().exists()) file2.getParentFile().mkdirs();
        if (file1.isDirectory()) {
            file2.mkdir();
            log += "建文件夹:" + file2.getPath() + "\n";
            File[] files = file1.listFiles();
            for (int i = 0; i < files.length; i++) {
                File ifile = files[i];
                String name = file2.getPath() + "/" + ifile.getName();
                File jfile = new File(name);
                log += copyFile(ifile, jfile);
            }
        } else {
            try {
                writeFile(file2, new FileInputStream(file1));
                log += "拷贝文件:" + file1.getName() + "\t>>  " + file2.getPath() + "\n";
            } catch (Exception e) {
                throw new RuntimeException("拷贝文件失败:" + log + "," + file1 + "到" + file2);
            }
        }
        return log;
    }

    public static boolean moveFile(File source, File target) {
        try {
            FileUtils.moveFile(source, target);
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * <b>功能： </b>获得文件的扩展名（不带.)
     *
     * @param fileName
     * @return ext（不带.)
     */
    private static String[] postfixs = new String[]{"JPG", "PNG", "JPEG", "GIF", "DOC", "DOCX", "XLS", "XLSX", "TXT", "ZIP", "RAR", "ISO"};

    public static String getPostfix(String fileName) {
        if (Validation.isEmpty(fileName)) throw new RuntimeException("获得文件名称的后缀失败,参数为空:" + fileName + ".");
        try {
            if (fileName.indexOf("?") != -1) {
                fileName = fileName.substring(0, fileName.lastIndexOf("?"));
            }
            if (fileName.lastIndexOf(".") != -1) {
                return fileName.substring(fileName.lastIndexOf(".") + 1).toUpperCase();
            } else if (fileName.lastIndexOf("?") != -1) {
                return fileName.substring(fileName.lastIndexOf("?") + 1).toUpperCase();
            } else {
                for (String postfix : postfixs) {
                    if (fileName.toUpperCase().endsWith(postfix)) {
                        return postfix;
                    }
                }
                return "TEMP";
            }
        } catch (Exception ex) {
            throw new RuntimeException("获得文件名称的后缀失败,名称不存在后缀:" + fileName + ".");
        }
    }

    /*创建文件夹*/

    public static File mkdirs(String file1, String file2) {
        File file = new File(file1, file2);
        if (!file.exists()) file.mkdirs();
        return file;
    }

    public static void writeFile(String filepath, InputStream stream) throws Exception {
        writeFile(new File(filepath), stream);
    }

    public static void writeFile(File file, InputStream stream) throws Exception {
        if (file.exists()) file.delete();
        try {
            FileOutputStream output = new FileOutputStream(file);
            try {
                IOUtils.copy(stream, output);
            } finally {
                IOUtils.closeQuietly(output);
            }
        } finally {
            IOUtils.closeQuietly(stream);
        }
    }


    //=======================FileUploader======================================================================Start

    /**
     * 生成临时文件 保存路径
     *
     * @param output
     * @return
     */
    private static File getTempFile(String output) {
        File tempFile = new File(TEMP_DIRECTORY, System.currentTimeMillis() + "." + FileUtility.getPostfix(output));
        return tempFile;
    }

    /**
     * 生成 相对的 文件存放路径
     *
     * @param fileid
     * @return
     */
    public static String generateDirectory(Long fileid) {
        StringBuffer directoryBuffer = new StringBuffer();
        directoryBuffer.append(fileid / (1024 * 1024 * 1024)).append("/");
        directoryBuffer.append(fileid / (1024 * 1024)).append("/");
        directoryBuffer.append(fileid / 1024).append("/");
        return directoryBuffer.toString();
    }


    /**
     * 生成 绝对的 文件存放路径
     *
     * @param fileid
     * @return
     */
    public static String generateDirectoryAbsolute(Long fileid) {
        String directoryPath = generateDirectory(fileid);
        File directory = new File(DIRECTORY, directoryPath);
        if (!directory.exists()) directory.mkdirs();
        return directory.getPath();
    }

    public static File generateDirectoryAbsoluteFull(Long fileid, String postfix) {
        File file = new File(generateDirectoryAbsolute(fileid), fileid + "." + postfix);
        return file;
    }

    public static void deleteByResourceId(final long id) {
        deleteByResourceId(id, true);
    }

    public static void deleteByResourceId(final long id, final boolean delSrcFile) {
        File directory = new File(generateDirectoryAbsolute(id));
        File[] files = directory.listFiles(new FilenameFilter() {
            public boolean accept(File dir, String name) {
                if ((delSrcFile && name.startsWith(id + ".")) || name.startsWith(id + "_")) {
                    return true;
                }
                return false;
            }
        });
        for (File file : files) {
            file.delete();
            logger.debug("完成文件删除:" + file.getAbsolutePath());
        }
    }


    /**
     * 保存下载文件到临时目录
     *
     * @param input
     * @return
     */
    private static HttpClient httpClient = new HttpClient();

    public static File writeFileDownloader(String input) {
        httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(5000);
        httpClient.getHttpConnectionManager().getParams().setSoTimeout(5000);
        GetMethod method = new GetMethod(com.enterprise.support.utility.Function.encode(input, "UTF-8"));
        try {
            File saveFile = getTempFile(input);
            int index = input.indexOf("/", 7);
            httpClient.getHostConfiguration().setHost(index == -1 ? input.substring(7) : input.substring(7, index));
            method.getParams().setSoTimeout(5000);
            method.setRequestHeader("Referer", input);
            method.setRequestHeader("Connection", "close");
            httpClient.executeMethod(method);
            FileUtility.writeFile(saveFile, method.getResponseBodyAsStream());
            return saveFile;
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            method.releaseConnection();
        }
        return null;
    }

    /**
     * 保存上传文件 到临时目录
     *
     * @param input
     * @return
     */
    public static File writeFileUploader(FileItem input) {
        try {
            File saveFile = getTempFile(input.getName());
            input.write(saveFile);
            return saveFile;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }


    public static File[] getUploaderFiles(String path) {
        String filename = getFileNameChop(path).replace("." + getPostfix(path), "");
        String postfix = getPostfix(path);
        final File source = new File(path);
        final String regex = "(?i)" + filename + "(\\_[0-9]+x[0-9]+)?\\." + postfix;
        return source.getParentFile().listFiles(new FileFilter() {
            public boolean accept(File file) {
                return (file.isFile() && file.getName().matches(regex));
            }
        });
    }
    //=======================FileUploader======================================================================End

    public static void mask(String logosrc, String targetfilepath) {
        /*ImageMagick.mask(logosrc, targetfilepath);*/
    }

    public static void maskfont(String targetfilepath) {
        /*ImageMagick.maskfont(targetfilepath);*/
    }


    public static InputStream loadJarResources(String filepath) {
        return FileUtility.class.getResourceAsStream("/config/" + filepath);
    }

    /*过滤无效字符*/
    public static String xmlfilter(String xmlStr) {
        StringBuilder sb = new StringBuilder();
        char[] chs = xmlStr.toCharArray();
        for (char ch : chs) {

            if ((ch == 0x9) || (ch == 0xA) || (ch == 0xD)
                    || ((ch >= 0x20) && (ch <= 0xD7FF))
                    || ((ch >= 0xE000) && (ch <= 0xFFFD))
                    || ((ch >= 0x10000) && (ch <= 0x10FFFF)))
                sb.append(ch);
            /*if ((ch >= 0x00 && ch <= 0x08)
                    || (ch >= 0x0b && ch <= 0x0c)
                    || (ch >= 0x0e && ch <= 0x1f)) {
                //eat...
            } else if (ch != 0xddfd && ch != 0xd862 && ch != 0xd8e8) {
                sb.append(ch);
            }*/
        }
        return sb.toString().replace("&#8<", "<");
    }

    public static Document parseDocumentByString(String result) {
        try {
            Document document = null;
            factory.setValidating(false);
            DocumentBuilder builder = null;
            builder = factory.newDocumentBuilder();
            document = builder.parse(new ByteArrayInputStream(result.getBytes("UTF-8")));
            return document;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    public static void parseDocumentByString(String result, DefaultHandler defaultHandler) {
        try {
            SAXParserFactory sf = SAXParserFactory.newInstance();
            SAXParser sp = sf.newSAXParser();
            sp.parse(new ByteArrayInputStream(result.getBytes("UTF-8")), defaultHandler);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }


    public static String xpath(String expression, String result) {
        try {
            return xpath.evaluate(expression, parseDocumentByString(result)).toString();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return "";
    }

    public static String xpath(String expression, Document document) {
        try {
            return xpath.evaluate(expression, document).toString();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return "";
    }

    public static String xpathDropElement(String xpath, String stringDocument) {
        try {
            org.dom4j.Document document = org.dom4j.DocumentHelper.parseText(stringDocument);
            List<org.dom4j.Element> elements = document.selectNodes(xpath);
            for (org.dom4j.Element element : elements) {
                element.getParent().remove(element);
            }
            stringDocument = document.asXML();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return stringDocument;
    }


    /**
     * 从input里面读取数据然后写入output，读完后自动关闭流。     * @param input inputStream     * @param output outputStream     *
     */
    public static void write(InputStream input, OutputStream output) throws IOException {
        write(input, output, true);
    }

    /**
     * 自动从inputstream里面读数据，然后写到outputstream里面去。     * @param input inputstream     * @param output outputstream     * @param close 读完后是否自动关闭流。     *
     */
    public static void write(InputStream input, OutputStream output, boolean close) throws IOException {
        byte[] b = new byte[1024];
        int len = input.read(b);
        while (len != -1) {
            output.write(b, 0, len);
            len = input.read(b);
        }
        output.flush();
        if (close) {
            input.close();
            output.close();
        }
    }


    public static String readHttp(String address, String charset) {
        try {
            URL url = new URL(address);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setDoOutput(true);
            System.setProperty("sun.net.client.defaultConnectTimeout", "5000");
            System.setProperty("sun.net.client.defaultReadTimeout", "5000");
            String result = readStream(conn.getInputStream(), charset);
            conn.disconnect();
            return result;
        } catch (Exception ex) {
            ex.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
        return null;
    }

    public static void main(String[] args) throws SAXException, ParserConfigurationException, XPathExpressionException, DocumentException {
        //System.out.println(xpathDropElement("//div[3]", "<root><div>阿斯顿飞</div><div>2</div><div>3</div><div>4</div></root>"));
        writeFileDownloader("http://adsfasdf.com");
    }

}
